package com.starsea.book.ui.book.read.config

import android.annotation.SuppressLint
import android.content.DialogInterface
import android.graphics.Color
import android.graphics.PorterDuff
import android.net.Uri
import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.SeekBar
import com.jaredrummler.android.colorpicker.ColorPickerDialog
import com.starsea.book.R
import com.starsea.book.base.BaseDialogFragment
import com.starsea.book.constant.EventBus
import com.starsea.book.databinding.DialogEditTextBinding
import com.starsea.book.databinding.DialogReadBgTextBinding
import com.starsea.book.databinding.ItemBgImageBinding
import com.starsea.book.help.DefaultData
import com.starsea.book.help.config.ReadBookConfig
import com.starsea.book.help.http.newCallResponseBody
import com.starsea.book.help.http.okHttpClient
import com.starsea.book.lib.dialogs.SelectItem
import com.starsea.book.lib.dialogs.alert
import com.starsea.book.lib.dialogs.selector
import com.starsea.book.lib.theme.bottomBackground
import com.starsea.book.lib.theme.getPrimaryTextColor
import com.starsea.book.lib.theme.getSecondaryTextColor
import com.starsea.book.ui.book.read.ReadBookActivity
import com.starsea.book.ui.file.HandleFileContract
import com.starsea.book.ui.widget.seekbar.SeekBarChangeListener
import com.starsea.book.utils.*
import com.starsea.book.utils.viewbindingdelegate.viewBinding
import splitties.init.appCtx

import java.io.FileOutputStream

class BgTextConfigDialog : BaseDialogFragment(R.layout.dialog_read_bg_text) {

    companion object {
        const val TEXT_COLOR = 121
        const val BG_COLOR = 122
    }

    private val binding by viewBinding(DialogReadBgTextBinding::bind)
    private val configFileName = "readConfig.zip"
    private val adapter by lazy { BgAdapter(requireContext(), secondaryTextColor) }
    private var primaryTextColor = 0
    private var secondaryTextColor = 0
    private val importFormNet = "网络导入"
    private val selectBgImage = registerForActivityResult(SelectImageContract()) {
        it.uri?.let { uri ->
            setBgFromUri(uri)
        }
    }
//    private val selectExportDir = registerForActivityResult(HandleFileContract()) {
//        it.uri?.let { uri ->
//            exportConfig(uri)
//        }
//    }
    private val selectImportDoc = registerForActivityResult(HandleFileContract()) {
        it.uri?.let { uri ->
            if (uri.toString() == importFormNet) {
                importNetConfigAlert()
            } else {
                importConfig(uri)
            }
        }
    }

    override fun onStart() {
        super.onStart()
        dialog?.window?.run {
            clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
            setBackgroundDrawableResource(R.color.background)
            decorView.setPadding(0, 0, 0, 0)
            val attr = attributes
            attr.dimAmount = 0.0f
            attr.gravity = Gravity.BOTTOM
            attributes = attr
            setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
        }
    }

    override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
        (activity as ReadBookActivity).bottomDialog++
        initView()
        initData()
        initEvent()
    }

    override fun onDismiss(dialog: DialogInterface) {
        super.onDismiss(dialog)
        ReadBookConfig.save()
        (activity as ReadBookActivity).bottomDialog--
    }

    private fun initView() = binding.run {
        val bg = requireContext().bottomBackground
        val isLight = ColorUtils.isColorLight(bg)
        primaryTextColor = requireContext().getPrimaryTextColor(isLight)
        secondaryTextColor = requireContext().getSecondaryTextColor(isLight)
        rootView.setBackgroundColor(bg)
        tvNameTitle.setTextColor(primaryTextColor)
        tvName.setTextColor(secondaryTextColor)
        ivEdit.setColorFilter(secondaryTextColor, PorterDuff.Mode.SRC_IN)
        tvRestore.setTextColor(primaryTextColor)
        swDarkStatusIcon.setTextColor(primaryTextColor)
        swUnderline.setTextColor(primaryTextColor)
        ivImport.setColorFilter(primaryTextColor, PorterDuff.Mode.SRC_IN)
        ivExport.setColorFilter(primaryTextColor, PorterDuff.Mode.SRC_IN)
        ivDelete.setColorFilter(primaryTextColor, PorterDuff.Mode.SRC_IN)
        tvBgAlpha.setTextColor(primaryTextColor)
        tvBgImage.setTextColor(primaryTextColor)
        recyclerView.adapter = adapter
        adapter.addHeaderView {
            ItemBgImageBinding.inflate(layoutInflater, it, false).apply {
                tvName.setTextColor(secondaryTextColor)
                tvName.text = getString(R.string.select_image)
                ivBg.setImageResource(R.drawable.ic_image)
                ivBg.setColorFilter(primaryTextColor, PorterDuff.Mode.SRC_IN)
                root.setOnClickListener {
                    selectBgImage.launch()
                }
            }
        }
        requireContext().assets.list("bg")?.let {
            adapter.setItems(it.toList())
        }
    }

    @SuppressLint("InflateParams")
    private fun initData() = with(ReadBookConfig.durConfig) {
        binding.tvName.text = name.ifBlank { "文字" }
        binding.swDarkStatusIcon.isChecked = curStatusIconDark()
        binding.swUnderline.isChecked = underline
        binding.sbBgAlpha.progress = bgAlpha
    }

    @SuppressLint("InflateParams")
    private fun initEvent() = with(ReadBookConfig.durConfig) {
        binding.ivEdit.setOnClickListener {
            alert(R.string.style_name) {
                val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
                    editView.hint = "name"
                    editView.setText(ReadBookConfig.durConfig.name)
                }
                customView { alertBinding.root }
                okButton {
                    alertBinding.editView.text?.toString()?.let {
                        binding.tvName.text = it
                        ReadBookConfig.durConfig.name = it
                    }
                }
                cancelButton()
            }
        }
        binding.tvRestore.setOnClickListener {
            val defaultConfigs = DefaultData.readConfigs
            val layoutNames = defaultConfigs.map { it.name }
            context?.selector("选择预设布局", layoutNames) { _, i ->
                if (i >= 0) {
                    ReadBookConfig.durConfig = defaultConfigs[i].copy()
                    initData()
                    postEvent(EventBus.UP_CONFIG, true)
                }
            }
        }
        binding.swDarkStatusIcon.setOnCheckedChangeListener { _, isChecked ->
            setCurStatusIconDark(isChecked)
            (activity as? ReadBookActivity)?.upSystemUiVisibility()
        }
        binding.swUnderline.setOnCheckedChangeListener { _, isChecked ->
            underline = isChecked
            postEvent(EventBus.UP_CONFIG, true)
        }
        binding.tvTextColor.setOnClickListener {
            ColorPickerDialog.newBuilder()
                .setColor(curTextColor())
                .setShowAlphaSlider(false)
                .setDialogType(ColorPickerDialog.TYPE_CUSTOM)
                .setDialogId(TEXT_COLOR)
                .show(requireActivity())
        }
        binding.tvBgColor.setOnClickListener {
            val bgColor =
                if (curBgType() == 0) Color.parseColor(curBgStr())
                else Color.parseColor("#015A86")
            ColorPickerDialog.newBuilder()
                .setColor(bgColor)
                .setShowAlphaSlider(false)
                .setDialogType(ColorPickerDialog.TYPE_CUSTOM)
                .setDialogId(BG_COLOR)
                .show(requireActivity())
        }
        binding.ivImport.setOnClickListener {
            selectImportDoc.launch {
                mode = HandleFileContract.FILE
                title = getString(R.string.import_str)
                allowExtensions = arrayOf("zip")
                otherActions = arrayListOf(SelectItem(importFormNet, -1))
            }
        }
//        binding.ivExport.setOnClickListener {
//            selectExportDir.launch {
//                title = getString(R.string.export_str)
//            }
//        }
        binding.ivDelete.setOnClickListener {
            if (ReadBookConfig.deleteDur()) {
                postEvent(EventBus.UP_CONFIG, true)
                dismissAllowingStateLoss()
            } else {
                toastOnUi("数量已是最少,不能删除.")
            }
        }
        binding.sbBgAlpha.setOnSeekBarChangeListener(object : SeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
                ReadBookConfig.bgAlpha = progress
                postEvent(EventBus.UP_CONFIG, false)
            }

            override fun onStopTrackingTouch(seekBar: SeekBar) {
                postEvent(EventBus.UP_CONFIG, false)
            }
        })
    }

//    private fun exportConfig(uri: Uri) {
//        val exportFileName = if (ReadBookConfig.config.name.isBlank()) {
//            configFileName
//        } else {
//            "${ReadBookConfig.config.name}.zip"
//        }
//        execute {
//            val exportFiles = arrayListOf<File>()
//            val configDir = requireContext().externalCache.getFile("readConfig")
//            configDir.createFolderReplace()
//            val configFile = configDir.getFile("readConfig.json")
//            configFile.createFileReplace()
//            configFile.writeText(GSON.toJson(ReadBookConfig.getExportConfig()))
//            exportFiles.add(configFile)
//            val fontPath = ReadBookConfig.textFont
//            if (fontPath.isNotEmpty()) {
//                val fontName = FileUtils.getName(fontPath)
//                val fontBytes = fontPath.parseToUri().readBytes(requireContext())
//                fontBytes.let {
//                    val fontExportFile = FileUtils.createFileIfNotExist(configDir, fontName)
//                    fontExportFile.writeBytes(it)
//                    exportFiles.add(fontExportFile)
//                }
//            }
//            if (ReadBookConfig.durConfig.bgType == 2) {
//                val bgName = FileUtils.getName(ReadBookConfig.durConfig.bgStr)
//                val bgFile = File(ReadBookConfig.durConfig.bgStr)
//                if (bgFile.exists()) {
//                    val bgExportFile = File(FileUtils.getPath(configDir, bgName))
//                    bgFile.copyTo(bgExportFile)
//                    exportFiles.add(bgExportFile)
//                }
//            }
//            if (ReadBookConfig.durConfig.bgTypeNight == 2) {
//                val bgName = FileUtils.getName(ReadBookConfig.durConfig.bgStrNight)
//                val bgFile = File(ReadBookConfig.durConfig.bgStrNight)
//                if (bgFile.exists()) {
//                    val bgExportFile = File(FileUtils.getPath(configDir, bgName))
//                    bgFile.copyTo(bgExportFile)
//                    exportFiles.add(bgExportFile)
//                }
//            }
//            if (ReadBookConfig.durConfig.bgTypeEInk == 2) {
//                val bgName = FileUtils.getName(ReadBookConfig.durConfig.bgStrEInk)
//                val bgFile = File(ReadBookConfig.durConfig.bgStrEInk)
//                if (bgFile.exists()) {
//                    val bgExportFile = File(FileUtils.getPath(configDir, bgName))
//                    bgFile.copyTo(bgExportFile)
//                    exportFiles.add(bgExportFile)
//                }
//            }
//            val configZipPath = FileUtils.getPath(requireContext().externalCache, configFileName)
//            if (ZipUtils.zipFiles(exportFiles, File(configZipPath))) {
//                if (uri.isContentScheme()) {
//                    DocumentFile.fromTreeUri(requireContext(), uri)?.let { treeDoc ->
//                        treeDoc.findFile(exportFileName)?.delete()
//                        treeDoc.createFile("", exportFileName)
//                            ?.writeBytes(requireContext(), File(configZipPath).readBytes())
//                    }
//                } else {
//                    val exportPath = FileUtils.getPath(File(uri.path!!), exportFileName)
//                    FileUtils.delete(exportPath)
//                    FileUtils.createFileIfNotExist(exportPath)
//                        .writeBytes(File(configZipPath).readBytes())
//                }
//            }
//        }.onSuccess {
//            toastOnUi("导出成功, 文件名为 $exportFileName")
//        }.onError {
//            it.printOnDebug()
//            AppLog.put("导出失败:${it.localizedMessage}", it)
//            longToast("导出失败:${it.localizedMessage}")
//        }
//    }

    @SuppressLint("InflateParams")
    private fun importNetConfigAlert() {
        alert("输入地址") {
            val alertBinding = DialogEditTextBinding.inflate(layoutInflater)
            customView { alertBinding.root }
            okButton {
                alertBinding.editView.text?.toString()?.let { url ->
                    importNetConfig(url)
                }
            }
            noButton()
        }
    }

    private fun importNetConfig(url: String) {
        execute {
            okHttpClient.newCallResponseBody {
                url(url)
            }.bytes().let {
                importConfig(it)
            }
        }.onError {
            longToast(it.stackTraceStr)
        }
    }

    private fun importConfig(uri: Uri) {
        execute {
            importConfig(uri.readBytes(requireContext()))
        }.onError {
            it.printOnDebug()
            longToast("导入失败:${it.localizedMessage}")
        }
    }

    private fun importConfig(byteArray: ByteArray) {
        execute {
            ReadBookConfig.import(byteArray).getOrThrow()
        }.onSuccess {
            ReadBookConfig.durConfig = it
            postEvent(EventBus.UP_CONFIG, true)
            toastOnUi("导入成功")
        }.onError {
            it.printOnDebug()
            longToast("导入失败:${it.localizedMessage}")
        }
    }

    private fun setBgFromUri(uri: Uri) {
        readUri(uri) { fileDoc, inputStream ->
            kotlin.runCatching {
                var file = requireContext().externalFiles
                val suffix = fileDoc.name.substringAfterLast(".")
                val fileName = uri.inputStream(requireContext()).getOrThrow().use {
                    MD5Utils.md5Encode(it) + ".$suffix"
                }
                file = FileUtils.createFileIfNotExist(file, "bg", fileName)
                FileOutputStream(file).use { outputStream ->
                    inputStream.copyTo(outputStream)
                }
                ReadBookConfig.durConfig.setCurBg(2, fileName)
                postEvent(EventBus.UP_CONFIG, false)
            }.onFailure {
                appCtx.toastOnUi(it.localizedMessage)
            }
        }
    }
}